using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;

using WL.Think.Abp.Dto;
using WL.Think.Abp.Localization;

namespace WL.Think.Abp.Services;

/// <summary>
/// 基础应用服务
/// </summary>
public abstract class ThinkAppService : ApplicationService, IThinkAppService
{
    protected ThinkAppService()
    {
        LocalizationResource = typeof(ThinkResource);
    }
}


/// <summary>
/// 基础应用服务
/// </summary>
/// <typeparam name="TEntity">实体类</typeparam>
/// <typeparam name="TGetOutputDto">实体对应DTO</typeparam>
/// <typeparam name="TGetListInput">分页查询DTO</typeparam>
/// <typeparam name="TCreateInput">创建实体DTO</typeparam>
/// <typeparam name="TUpdateInput">更新实体DTO</typeparam>
public abstract class ThinkAppService<TEntity, TGetOutputDto, TGetListInput, TCreateInput, TUpdateInput> :
    CrudAppService<TEntity, TGetOutputDto, Guid, TGetListInput, TCreateInput, TUpdateInput>,
    IThinkAppService<TGetOutputDto, TGetListInput, TCreateInput, TUpdateInput>
    where TEntity : class, IEntity<Guid>
    where TGetListInput : BasePagedDto
    where TCreateInput : class
    where TUpdateInput : class
{
    protected new IRepository<TEntity, Guid> Repository { get; }

    protected ThinkAppService(IRepository<TEntity, Guid> repository) : base(repository)
    {
        Repository = repository;
        LocalizationResource = typeof(ThinkResource);
    }

    public override async Task<PagedResultDto<TGetOutputDto>> GetListAsync(TGetListInput input)
    {
        var result = await base.GetListAsync(input);
        await AfterGetListHookAsync(result, input);
        return result;
    }

    public override async Task<TGetOutputDto> CreateAsync(TCreateInput input)
    {
        await CheckCreatePolicyAsync();
        var entity = await MapToEntityAsync(input);
        TryToSetTenantId(entity);
        await BeforeCreateHookAsync(entity, input);
        await Repository.InsertAsync(entity, autoSave: true);
        await AfterCreateHookAsync(entity, input);
        return await MapToGetOutputDtoAsync(entity);
    }

    public override async Task<TGetOutputDto> UpdateAsync(Guid id, TUpdateInput input)
    {
        await CheckUpdatePolicyAsync();
        var entity = await GetEntityByIdAsync(id);
        await MapToEntityAsync(input, entity);
        await BeforeUpdateHookAsync(entity, input);
        await Repository.UpdateAsync(entity, true);
        await AfterUpdateHookAsync(entity, input);
        return await MapToGetOutputDtoAsync(entity);
    }

    public override async Task DeleteAsync(Guid id)
    {
        await CheckDeletePolicyAsync();
        var entity = await Repository.GetAsync(id);
        await BeforeDeleteHookAsync(entity);
        await DeleteByIdAsync(id);
        await AfterDeleteHookAsync(entity);
    }

    /// <summary>
    /// 获取分页列表后执行
    /// </summary>
    /// <param name="dtos"></param>
    /// <param name="input"></param>
    /// <returns></returns>
    protected virtual Task AfterGetListHookAsync(PagedResultDto<TGetOutputDto> result, TGetListInput input)
    {
        return Task.CompletedTask;
    }

    /// <summary>
    /// 创建之前钩子
    /// </summary>
    /// <param name="entity"></param>
    /// <returns></returns>
    protected virtual Task BeforeCreateHookAsync(TEntity entity, TCreateInput input)
    {
        return Task.CompletedTask;
    }

    /// <summary>
    /// 创建之后钩子
    /// </summary>
    /// <param name="entity"></param>
    /// <returns></returns>
    protected virtual Task AfterCreateHookAsync(TEntity entity, TCreateInput input)
    {
        return Task.CompletedTask;
    }

    /// <summary>
    /// 更新之前钩子
    /// </summary>
    /// <param name="entity"></param>
    /// <param name="input"></param>
    /// <returns></returns>
    protected virtual Task BeforeUpdateHookAsync(TEntity entity, TUpdateInput input)
    {
        return Task.CompletedTask;
    }

    /// <summary>
    /// 更新之后钩子
    /// </summary>
    /// <param name="entity"></param>
    /// <param name="input"></param>
    /// <returns></returns>
    protected virtual Task AfterUpdateHookAsync(TEntity entity, TUpdateInput input)
    {
        return Task.CompletedTask;
    }

    /// <summary>
    /// 删除之前钩子
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    protected virtual Task BeforeDeleteHookAsync(TEntity entity)
    {
        return Task.CompletedTask;
    }

    /// <summary>
    /// 删除之后钩子
    /// </summary>
    /// <param name="entity"></param>
    /// <returns></returns>
    protected virtual Task AfterDeleteHookAsync(TEntity entity)
    {
        return Task.CompletedTask;
    }

    /// <summary>
    /// 对象映射
    /// </summary>
    /// <typeparam name="TEntitySource"></typeparam>
    /// <typeparam name="TEntityTarget"></typeparam>
    /// <param name="source"></param>
    /// <returns></returns>
    protected Task<TEntityTarget> MapObjectAsync<TEntitySource, TEntityTarget>(TEntitySource source)
    {
        var target = ObjectMapper.Map<TEntitySource, TEntityTarget>(source);
        return Task.FromResult(target);
    }

    /// <summary>
    /// 对象映射
    /// </summary>
    /// <typeparam name="TEntitySource"></typeparam>
    /// <typeparam name="TEntityTarget"></typeparam>
    /// <param name="source"></param>
    /// <param name="target"></param>
    /// <returns></returns>
    protected Task<TEntityTarget> MapObjectAsync<TEntitySource, TEntityTarget>(TEntitySource source,TEntityTarget target)
    {
        target = ObjectMapper.Map(source, target);
        return Task.FromResult(target);
    }

    /// <summary>
    /// 集合映射
    /// </summary>
    /// <typeparam name="TEntitySource"></typeparam>
    /// <typeparam name="TEntityTarget"></typeparam>
    /// <param name="source"></param>
    /// <returns></returns>
    protected async Task<List<TEntityTarget>> MapListAsync<TEntitySource, TEntityTarget>(IEnumerable<TEntitySource> sources)
    {
        List<TEntityTarget> targets = new List<TEntityTarget>();
        foreach (TEntitySource source in sources)
        {
            targets.Add(await MapObjectAsync<TEntitySource,TEntityTarget>(source).ConfigureAwait(continueOnCapturedContext: false));
        }

        return targets;
    }

    /// <summary>
    /// 关闭软删除,会直接删除数据库数据，注意执行完成后要记得恢复，使用 using 操作
    /// </summary>
    /// <returns></returns>
    protected IDisposable CloseSoftDelete()
    {
        return DataFilter.Disable<ISoftDelete>();   
    }

    /// <summary>
    /// 关闭软删除
    /// </summary>
    /// <param name="action"></param>
    protected void CloseSoftDelete(Action action)
    {
        using (DataFilter.Disable<ISoftDelete>())
        {
            action?.Invoke();
        }
    }
}

/// <summary>
/// 基础应用服务
/// </summary>
/// <typeparam name="TEntity">实体类</typeparam>
/// <typeparam name="TGetOutputDto">实体对应DTO</typeparam>
/// <typeparam name="TGetListInput">分页查询DTO</typeparam>
/// <typeparam name="TCreateInput">创建实体DTO</typeparam>
public abstract class ThinkAppService<TEntity, TGetOutputDto, TGetListInput, TCreateInput> : 
    ThinkAppService<TEntity, TGetOutputDto, TGetListInput, TCreateInput, TCreateInput>,
    IThinkAppService<TGetOutputDto, TGetListInput, TCreateInput>
    where TEntity : class, IEntity<Guid>
    where TGetListInput : BasePagedDto
    where TCreateInput : class
{
    protected ThinkAppService(IRepository<TEntity, Guid> repository) : base(repository)
    {
    }
}


/// <summary>
/// 基础应用服务
/// </summary>
/// <typeparam name="TEntity">实体类</typeparam>
/// <typeparam name="TGetOutputDto">实体对应DTO</typeparam>
/// <typeparam name="TGetListInput">分页查询DTO</typeparam>
public abstract class ThinkAppService<TEntity, TGetOutputDto, TCreateInput> : 
    ThinkAppService<TEntity, TGetOutputDto, BasePagedDto, TCreateInput>,
    IThinkAppService<TGetOutputDto, TCreateInput>
    where TEntity : class, IEntity<Guid>
    where TCreateInput : class

{
    protected ThinkAppService(IRepository<TEntity, Guid> repository) : base(repository)
    {
    }
}


/// <summary>
/// 基础应用服务
/// </summary>
/// <typeparam name="TEntity">实体类</typeparam>
/// <typeparam name="TGetOutputDto">实体对应DTO</typeparam>
public abstract class ThinkAppService<TEntity, TGetOutputDto> : 
    ThinkAppService<TEntity, TGetOutputDto, TGetOutputDto>,
    IThinkAppService<TGetOutputDto>
    where TEntity : class, IEntity<Guid>
    where TGetOutputDto : class
{
    protected ThinkAppService(IRepository<TEntity, Guid> repository) : base(repository)
    {
    }
}


/// <summary>
/// 基础应用服务
/// </summary>
/// <typeparam name="TEntity">实体类</typeparam>
public abstract class ThinkAppService<TEntity> : 
    ThinkAppService<TEntity, TEntity>,
    IThinkAppService<TEntity>
    where TEntity : class, IEntity<Guid>
{
    protected ThinkAppService(IRepository<TEntity, Guid> repository) : base(repository)
    {
    }
}
